/*****************************************************************************************
 * Aware : an Asynchonous Aware-Oriented Software Architecture
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *****************************************************************************************/
package dexter.aware;

import java.net.InetAddress;

import dexter.net.Producer;
import dexter.net.msg.RequestMessage;
import dexter.util.Configuration;
import dexter.aware.msg.StateParams;
import dexter.aware.util.Instrumentation;
import dexter.core.host.HostAddress;

/**
 * Sensor entity class
 * 
 * @author Ruben Mondejar <rmondejara@uoc.edu>
 */
public class Sensor extends Thread {

    	private static String FRONT_HOSTNAME = Configuration.getFrontHostName();
    	private static int FRONT_PORT = Configuration.getFrontPort();
    	private static HostAddress front;
    	
    	private static int PORT = Configuration.getCoordPort();    	
    	private static String HOSTNAME = "localhost"; 
	    private static final int SEND_PERIOD = Configuration.getSensorPeriod();
	    
		private Producer producer;
    	private boolean stop;
    	
    	/**
    	 * Creates a sensor instance with the monitor host handle
    	 */
    	public Sensor() {
    		try {
    		  HOSTNAME = InetAddress.getLocalHost().getHostName();
    		} catch(Exception e) {}  
    		this.front = new HostAddress(FRONT_HOSTNAME, FRONT_PORT);
    	    producer = new Producer(front);
    		this.stop = false;
    	}
    	
    	/**
    	 * Creates a sensor instance with the monitor host handle
    	 * @param host
    	 */
//    	public Sensor(HostAddress front) {
//    		try {
//      		  HOSTNAME = InetAddress.getLocalHost().getHostName();
//      		} catch(Exception e) {}  
//      		this.front = front;
//    	    producer = new Producer(front);
//    		this.stop = false;
//    	}
    	
    	public int[] evaluate() {
    		
    		int[] value = new int[]{100,100,100};
    		value[0] = evaluateCPU();
    	    value[1] = evaluateMem();
    	    value[2] = evaluateDisk();
    		
    		return value;
    	}
    	
    	private int evaluateCPU() {
    		int num = Instrumentation.getAvailableProcessors();
    		
    		double cpu = (Instrumentation.getSystemLoadAverage()*100);
    		//System.out.println("num : "+num+" + cpu : "+cpu);
    		int value = new Double(cpu).intValue()/num;
    		//normalize
    		if (value>100) {
    			int n = (value - (value%100))/100; //ex. 354 -> n=3
    			value = value / (n+1); //ex. 354 / 4 = 88;
    		}
    		
    		int freeCPU = 100 - value;
			return freeCPU;
		}
    	
    	private int evaluateMem() {
    		double free  = Instrumentation.getFreeMem()*100; 
    		double total = Instrumentation.getTotalMem();
    		int value = new Double(free / total).intValue(); 
    		//System.out.println("mem : "+value+" + total : "+total+" free : "+free);
    		//int value = (int) mem*100;
			return value;
		}
    	
    	private int evaluateDisk() {
    		double free  = Instrumentation.getFreeSpace()*100; 
    		double total = Instrumentation.getTotalSpace();
    		int value = new Double(free / total).intValue(); 
    		
			return value;
		}

    	/**
    	 * This thread evaluates the host state, produces a state message
    	 * and send it to monitor host, each time, periodically
    	 */
		public void run() {
			
			//System.out.println("Aware Sensor: Notifing state to " + host );

    		while(!stop) {
    			try {
    				sendCurrentState();
					
				} catch (Exception e) {
					System.out.println("Sensor error : Host <"+front+"> not reacheable");
					//e.printStackTrace();
				}
				
				try {
				  Thread.sleep(SEND_PERIOD);
				} catch (Exception e) {}  
    		}
    	}
	
	private void sendCurrentState() {
		
			int[] value = evaluate();    
			HostAddress host = new HostAddress(HOSTNAME, PORT);
			StateParams params = new StateParams(host, value);
			RequestMessage msg = new RequestMessage();
			msg.setParams(params);
		    System.out.println("Sending state to "+front);
			producer.send(front, msg);
			
	}

//	public static void main(String args[]){
//		
//		HostAddress host = new HostAddress(HOSTNAME,PORT);
//		Sensor sensor = new Sensor(host);	
//		int[] state = sensor.evaluate();
//		System.out.println("Initial state | CPU : "+state[0]+"% | MEM "+state[1]+"% | DISK "+state[2]+"%");
//		sensor.start();            
//    }




}
